package ufo.client


import api.action.{FireWeapon, EndTurn, Walk, Action}
import api.common.{Position}
import api.event._
import domain.{Being, BeingContainer}
import java.awt.event.{MouseEvent, MouseAdapter, ActionEvent}
import java.awt.{BorderLayout, Color, Graphics, Dimension}
import java.util.UUID
import api.{EventListener, ActionPerformer}
import javax.swing.{JButton, JToolBar, JComponent, JFrame}

class UfoClient(name: String, actionPerformer: ActionPerformer) extends JFrame("Ufo Client") with EventListener {
	var world: ClientWorld = null
	var worldComponent: WorldComponent = null

	def perform(position: Position, agressive: Boolean) = {
		def moveTo() = {
			val direction = world.selectedBeing.position.directionTo(position)

			if (direction != None) {
				actionPerformer.perform(Walk(world.selectedBeing.id, direction.get))
				println("Moved " + world.selectedBeing.id)
			}
		}

		def fireAt() = {
			actionPerformer.perform(FireWeapon(world.selectedBeing.id, position))
		}

		if (world.selectedBeing != null) {
			val being = world.findBeingAt(position)

			if (being != None) {
				if (agressive || being.get.clientId != world.clientId) {
					fireAt()
				}
			} else {
				moveTo()
			}

			worldComponent.repaint()
		}
	}

	def select(position: Position) = {
		val being = world.findBeingAt(position)

		if (being != None) {
			world.selectedBeing = being.get
			println("Selected " + world.selectedBeing.id)
		} else if (world.selectedBeing != null) {
			world.selectedBeing = null
		}

		worldComponent.repaint()
	}

	def notify(event : Event) = event match {
		case Initialize(width: Int, height: Int, clientId : UUID) => {
			world = new ClientWorld(width, height, clientId)

			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
			setLayout(new BorderLayout)

			val toolBar = new JToolBar()
			val endTurnButton = new JButton("End Turn")
			endTurnButton.addActionListener(new java.awt.event.ActionListener() {
				def actionPerformed(event: ActionEvent) {
					actionPerformer.perform(EndTurn())
				}
			})

			toolBar add endTurnButton

			worldComponent = new WorldComponent(actionPerformer, world)
			worldComponent.addMouseListener(new MouseAdapter {
				override def mousePressed(e: MouseEvent) = {
          val pos = new Position(e.getX / 20, e.getY / 20)
          if (e.getButton == MouseEvent.BUTTON1) {
  					select(pos)
          } else if (e.getButton == MouseEvent.BUTTON2) {
            perform(pos, false)
          }
				}
			})

			add(toolBar, BorderLayout.NORTH)
			add(worldComponent, BorderLayout.CENTER)
			pack
			setVisible(true)
		}

		case BeingMoved(beingId : UUID, position : Position) => {
			val being = world.getBeing(beingId)

			if (being.isDefined) {
				being.get.position = position
			} else {
				println("UNKNOWN BEING!!!! " + beingId)
			}

			worldComponent.repaint()
		}
		
		case BeingSpotted(beingId, position, clientId, hitPoints) => {
			val being = world.getBeing(beingId)

			if (being.isEmpty) {
				world.add(new ClientBeing(beingId, position, clientId, hitPoints))
			}

			worldComponent.repaint()
		}

		case BeingInjured(beingId, damage) => {
			val being = world.getBeing(beingId)

			if (being.isDefined) {
				being.get.hitPoints -= damage
			}

			worldComponent.repaint()
		}

		case BeingDies(beingId) => {
			val being = world.getBeing(beingId)

			if (being.isDefined) {
				being.get.hitPoints = 0
			}

			worldComponent.repaint()
		}

		case BeginTurn(clientId: UUID) => {
			world.myTurn = world.clientId equals clientId
			worldComponent.repaint()
		}
		case _ => {
			println(name + " did not understand: " + event)
		}
	}
}

class WorldComponent(actionPerformer: ActionPerformer, world: ClientWorld) extends JComponent {
	override def paint(g: Graphics) = {
		if (world.myTurn) {
			g.setColor(Color.BLUE)
		} else {
			g.setColor(Color.GRAY)
		}

		g.fillRect(0, 0, getWidth, getHeight)

		g.setColor(Color.BLACK)
		List.range(0, world.width).foreach(x => {
			g.drawLine(x * 20, 0, x * 20, getHeight)
		})

		List.range(0, world.height).foreach(y => {
			g.drawLine(0, y * 20, getWidth, y * 20)
		})

		world.beings.values.foreach(b => {
			val x = b.position.x * 20
			val y = b.position.y * 20

			if (b == world.selectedBeing) {
				g.setColor(Color.YELLOW)
			} else if (b.clientId == world.clientId) {
				g.setColor(Color.GREEN)
			} else {
				g.setColor(Color.RED)
			}
			
			if (b.hitPoints == 0) {
				g.setColor(g.getColor.darker)
			}

			g.fillOval(x, y, 20, 20)
		})
	}

	setPreferredSize(new Dimension(world.width * 20, world.height * 20))
}

class LazyloadActionPerformer extends ActionPerformer {
	var actionPerformer: ActionPerformer = null

	def set(actionPerformer:ActionPerformer) = {
		this.actionPerformer = actionPerformer
	}
	
	def perform(action : Action) = {
		actionPerformer.perform(action)
	}
}

class ClientWorld(val width : Int, val height : Int, val clientId : UUID) extends BeingContainer[ClientBeing] {
	var myTurn: Boolean = false
	var selectedBeing: ClientBeing = null
}

class ClientBeing(id : UUID, initialPosition : Position, val clientId: UUID, hitPoints : Int) extends Being(id, initialPosition, hitPoints) {
  var maxActionPoints = 5
  var actionPoints = maxActionPoints
}